/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** *****************************************************************************************************
 * \file     Uart_Ip.c                                                                                  *
 * \brief    AUTOSAR 4.3.1 MCAL UART Driver                                                             *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2024/10/29     <td>1.0.0                                                                     *
 * </table>                                                                                             *
 *******************************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

/********************************************************************************************************
 *                                      Include header files                                            *
 *******************************************************************************************************/
#include "RegHelper.h"
#include "SchM_Uart.h"
#include "Uart_Ip.h"
#include "Uart_Ip_Reg.h"
#if (STD_ON == UART_DMA_SUPPORT)
#include "Mcal_Cache.h"
#endif /* #if (STD_ON == UART_DMA_SUPPORT) */

/********************************************************************************************************
 *                                  Global Variable Declarations                                        *
 *******************************************************************************************************/
extern Uart_HandlerType * const Uart_Handler[CPU_MAX_CORE_NUMBER];
extern const uint8 channelMaxIdxOnCore[CPU_MAX_CORE_NUMBER];

/********************************************************************************************************
 *                                 Private Macro definition                                             *
 *******************************************************************************************************/
#define UART_SERIAL_MODE (0U)

#define UART_BM_INTR_TX_ERROR  BM_INTR0_TXFOVF

#define UART_BM_INTR_RX_ERROR                                         \
       (BM_INTR0_RXFOVF | BM_INTR0_RXFUDF |                           \
        BM_INTR0_PARITYERR | BM_INTR0_FRAMEERR |                      \
        BM_INTR0_BAUDRATEERR | BM_INTR0_NOISEERR)

#define UART_TIMEOUT_CNT 0x80000U

/********************************************************************************************************
 *                                  Private Function Declarations                                       *
 *******************************************************************************************************/
static inline Std_ReturnType Uart_Ip_ClearTxFifo(uint32 baseAddr);
static inline Std_ReturnType Uart_Ip_ClearRxFifo(uint32 baseAddr);
static inline void Uart_Ip_WaitTxIdle(uint32 baseAddr);
static inline void Uart_Ip_WaitRxIdle(uint32 baseAddr);
static uint32 Uart_Ip_GetClockFreq(uint8 Channel);
static inline uint32 Uart_Ip_BaudrateRoundOff(uint32 clkFreq, uint32 baudRate);
static void Uart_Ip_PutData(uint8 Channel);
static void Uart_Ip_GetData(uint8 Channel);
static Uart_StatusType Uart_Ip_CheckRecvErr(uint32 baseAddr);
static void Uart_Ip_SendDataUsingInt(uint8 Channel);
static void Uart_Ip_RecvDataUsingInt(uint8 Channel);
static inline void Uart_Ip_FinishSendDataUsingInt(uint8 Channel);
static inline void Uart_Ip_FinishRecvDataUsingInt(uint8 Channel);
#if (STD_ON == UART_DMA_SUPPORT)
static inline Std_ReturnType Uart_Ip_TxDmaReset(uint32 baseAddr);
static inline Std_ReturnType Uart_Ip_RxDmaReset(uint32 baseAddr);
static Std_ReturnType Uart_Ip_SendDataUsingDma(uint8 Channel);
static Std_ReturnType Uart_Ip_RecvDataUsingDma(uint8 Channel);
static void Uart_Ip_FinishSendDataUsingDma(uint8 Channel);
static void Uart_Ip_FinishRecvDataUsingDma(uint8 Channel);
void Uart_Irq_DmaSendComplete(Dma_ControllerStatusType status, void *context);
void Uart_Irq_DmaRecvComplete(Dma_ControllerStatusType status, void *context);
#endif /* #if (STD_ON == UART_DMA_SUPPORT) */
static void Uart_Ip_RxErrIrqHandler(uint8 Channel);
static void Uart_Ip_TxErrIrqHandler(uint8 Channel);
static void Uart_Ip_TxCompleteIrqHandler(uint8 Channel);
static void Uart_Ip_RxFullIrqHandler(uint8 Channel);
static void Uart_Ip_AutoBaudPassIrqHandler(uint8 Channel);
static void Uart_Ip_AutoBaudFailIrqHandler(uint8 Channel);

#define UART_START_SEC_CODE
#include "Uart_MemMap.h"
/********************************************************************************************************
 *                                  Global Function Declarations                                        *
 *******************************************************************************************************/
uint8 Uart_GetCoreId(void)
{
    /* Return the core ID. */
    return  Mcal_GetCpuIndex();
}

Std_ReturnType Uart_Ip_Init(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    volatile uint32 timeout = 0U;
    uint32 clkFreq;
    uint32 value;
    Std_ReturnType returnValue = E_OK;

    /* disable Tx & Rx */
    value = readl(baseAddr + UART_PCR0_OFF);
    value &= ~(BM_PCR0_TXEN | BM_PCR0_RXEN);
    writel(value, baseAddr + UART_PCR0_OFF);

    /* disable module */
    value = readl(baseAddr + UART_MCR0_OFF);
    value &= ~(BM_MCR0_MODEN | FM_MCR0_OPMOD);
    writel(value, baseAddr + UART_MCR0_OFF);

    /* config to serial mode*/
    value |= FV_MCR0_OPMOD(UART_SERIAL_MODE);
    writel(value, baseAddr + UART_MCR0_OFF);

    /* PCR0 configuration */
    value = readl(baseAddr + UART_PCR0_OFF);
    value &= ~(FM_PCR0_DATABIT | FM_PCR0_STOPBIT
                |  FM_PCR0_PARITYBIT  | BM_PCR0_ADDRBIT | BM_PCR0_TRANSFERMODE);
    value |= FV_PCR0_DATABIT(channelConfig->dataBit);
    value |= FV_PCR0_STOPBIT(channelConfig->stopBits);
    value |= FV_PCR0_PARITYBIT(channelConfig->parity);
    if (TRUE == channelConfig->addrBit)
    {
        value |= BM_PCR0_ADDRBIT;
    }
    if (UART_MODE_HALF_DUPLEX == channelConfig->duplexMode)
    {
        value |= BM_PCR0_TRANSFERMODE;
    }
    writel(value, baseAddr + UART_PCR0_OFF);

    /* PCR1 configuration */
    value = readl(baseAddr + UART_PCR1_OFF);
    value &= ~FM_PCR1_SAMPLERATE;
    value |= FV_PCR1_SAMPLERATE(channelConfig->sampleRate);
    writel(value, baseAddr + UART_PCR1_OFF);

    /* FCR0 configuration */
    value = readl(baseAddr + UART_FCR0_OFF);
    value &= ~FM_FCR0_TXWMLVL;
    value |= FV_FCR0_TXWMLVL(channelConfig->txwmlvl);
    writel(value, baseAddr + UART_FCR0_OFF);

    /* FCR1 configuration */
    value = readl(baseAddr + UART_FCR1_OFF);
    value &= ~FM_FCR1_RXWMLVL;
    value |= FV_FCR1_RXWMLVL(channelConfig->rxwmlvl);
    writel(value, baseAddr + UART_FCR1_OFF);

    /* disable interrupt & clear status */
    writel(0U, baseAddr + UART_INTEN0_OFF);
    writel(0xFFFFFFFFU, baseAddr + UART_INTR0_OFF);

    /* clear fifo */
    if (
#if (STD_ON == UART_DMA_SUPPORT)
        (E_OK != Uart_Ip_TxDmaReset(baseAddr))  ||
        (E_OK != Uart_Ip_RxDmaReset(baseAddr))  ||
#endif /* #if (STD_ON == UART_DMA_SUPPORT) */
        (E_OK != Uart_Ip_ClearTxFifo(baseAddr)) ||
        (E_OK != Uart_Ip_ClearRxFifo(baseAddr)))
    {
        returnValue = UART_E_TIMEOUT;
    }
    else
    {
        /* config Rx receive filter */
        value = readl(baseAddr + UART_PCR8_OFF);
        value |= BM_PCR8_RXSYNCEN;
        value &= ~FM_PCR8_RXFILTCTL;
        value |= FV_PCR8_RXFILTCTL(3U);
        writel(value, baseAddr + UART_PCR8_OFF);
        /* reset module */
        value = readl(baseAddr + UART_MCR0_OFF);
        value |= BM_MCR0_MODRST;
        writel(value, baseAddr + UART_MCR0_OFF);
        while ((0U != (value & BM_MCR0_MODRST)) &&
            (timeout <= UART_TIMEOUT_CNT))
        {
            value = readl(baseAddr + UART_MCR0_OFF);
            timeout++;
        }

        if (timeout > UART_TIMEOUT_CNT)
        {
            returnValue = UART_E_TIMEOUT;
        }
    }

    if (E_OK == returnValue)
    {
        if (UART_MODE_HALF_DUPLEX == channelConfig->duplexMode)
        {
            /* config Tx receive filter */
            value = readl(baseAddr + UART_PCR9_OFF);
            value |= BM_PCR9_RXSYNCEN;
            value &= ~FM_PCR9_RXFILTCTL;
            value |= FV_PCR9_RXFILTCTL(3U);
            writel(value, baseAddr + UART_PCR9_OFF);
            /* enable Rx, disable Tx */
            value = readl(baseAddr + UART_PCR0_OFF);
            value |=  BM_PCR0_RXEN;
            value &=  ~BM_PCR0_TXEN;
            writel(value, baseAddr + UART_PCR0_OFF);
        }
        else
        {
            /* enable Rx and Tx */
            value = readl(baseAddr + UART_PCR0_OFF);
            value |= (BM_PCR0_TXEN | BM_PCR0_RXEN);
            writel(value, baseAddr + UART_PCR0_OFF);
        }

        /* Enable uart module. */
        value = readl(baseAddr + UART_MCR0_OFF);
        value |= BM_MCR0_MODEN;
        writel(value, baseAddr + UART_MCR0_OFF);

        /* config baudrate */
        if (FALSE == channelConfig->autoBaud)
        {
            /* disable autobaud related interrupt */
            value = readl(baseAddr + UART_INTEN0_OFF);
            value &= ~(BM_INTEN0_ABRPASSE | BM_INTEN0_ABRFAILE);
            writel(value, baseAddr + UART_INTEN0_OFF);

            /* disable autobaud */
            value = readl(baseAddr + UART_PCR0_OFF);
            value &= ~BM_PCR0_ABREN;
            writel(value, baseAddr + UART_PCR0_OFF);

            /* set baudrate*/
            clkFreq = Uart_Ip_GetClockFreq(Channel);
            value = Uart_Ip_BaudrateRoundOff(clkFreq, channelConfig->baudRate);
            value = (readl(baseAddr + UART_PCR1_OFF) & (~FM_PCR1_BAUDRATECNT)) |
                    (value & FM_PCR1_BAUDRATECNT);
            writel(value, baseAddr + UART_PCR1_OFF);
            uartState->baudRate = channelConfig->baudRate;
            uartState->autoBaudState = UART_AUTOBAUD_STATE_NOT_USE;
        }
        else
        {
            /* set ABRCTL0 , ABRCTL1*/
            value = readl(baseAddr + UART_PCR0_OFF);
            value &= ~(FM_PCR0_ABRCTL0 | FM_PCR0_ABRCTL1);
            value |= FV_PCR0_ABRCTL0(0);
            value |= FV_PCR0_ABRCTL1(channelConfig->matchNum);
            writel(value, baseAddr + UART_PCR0_OFF);
            /* clear baudrate */
            value = readl(baseAddr + UART_PCR1_OFF);
            value &= ~FM_PCR1_BAUDRATECNT;
            writel(value, baseAddr + UART_PCR1_OFF);
            /* enable autobaud related interrupt */
            value = readl(baseAddr + UART_INTEN0_OFF);
            value |= BM_INTEN0_ABRPASSE | BM_INTEN0_ABRFAILE;
            writel(value, baseAddr + UART_INTEN0_OFF);
            /* enable autobaud */
            value = readl(baseAddr + UART_PCR0_OFF);
            value |= BM_PCR0_ABREN;
            writel(value, baseAddr + UART_PCR0_OFF);
            uartState->autoBaudState = UART_AUTOBAUD_STATE_BUSY;
        }
    }

    return returnValue;
}

void Uart_Ip_Deinit(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    uint32 value;

    /* wait idle */
    Uart_Ip_WaitTxIdle(baseAddr);
    Uart_Ip_WaitRxIdle(baseAddr);

    /* disable interrupt & clear status */
    writel(0U, baseAddr + UART_INTEN0_OFF);
    writel(0xFFFFFFFFU, baseAddr + UART_INTR0_OFF);

    /* disable Tx & Rx */
    value = readl(baseAddr + UART_PCR0_OFF);
    value &= ~(BM_PCR0_TXEN | BM_PCR0_RXEN);
    writel(value, baseAddr + UART_PCR0_OFF);

    /* disable module */
    value = readl(baseAddr + UART_MCR0_OFF);
    value &= ~(BM_MCR0_MODEN | FM_MCR0_OPMOD);
    writel(value, baseAddr + UART_MCR0_OFF);

}

Std_ReturnType Uart_Ip_SetBaudrate(uint8 Channel, Uart_BaudrateType Baudrate)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    Std_ReturnType returnValue = E_OK;
    uint32 clkFreq = 0U;
    uint32 value;

    if ((UART_STATUS_BUSY == Uart_Ip_GetTransmitStatus(Channel, NULL_PTR)) ||
        (UART_STATUS_BUSY == Uart_Ip_GetReceiveStatus(Channel, NULL_PTR)))
    {
        /* channel busy */
        returnValue = UART_E_CHANNEL_BUSY;
    }
    else
    {
        /* disable autobaud related interrupt */
        value = readl(baseAddr + UART_INTEN0_OFF);
        value &= ~(BM_INTEN0_ABRPASSE | BM_INTEN0_ABRFAILE);
        writel(value, baseAddr + UART_INTEN0_OFF);

        /* disable autobaud */
        value = readl(baseAddr + UART_PCR0_OFF);
        value &= ~(BM_PCR0_ABREN);
        writel(value, baseAddr + UART_PCR0_OFF);

        uartState->autoBaudState = UART_AUTOBAUD_STATE_NOT_USE;

        /* set baudrate*/
        clkFreq = Uart_Ip_GetClockFreq(Channel);
        uartState->baudRate = Baudrate;
        value = Uart_Ip_BaudrateRoundOff(clkFreq, Baudrate);
        value = (readl(baseAddr + UART_PCR1_OFF) & (~FM_PCR1_BAUDRATECNT)) |
                (value & FM_PCR1_BAUDRATECNT);
        writel(value, baseAddr + UART_PCR1_OFF);
    }

    return returnValue;
}

void Uart_Ip_GetBaudrate(uint8 Channel, uint32 * Baudrate)
{
    uint8 coreId = Uart_GetCoreId();
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];

    *Baudrate = uartState->baudRate;

    return ;
}

Std_ReturnType Uart_Ip_SyncSend(uint8 Channel, const uint8* Buffer, uint32 BufferSize, uint32 Timeout)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    Std_ReturnType returnValue = UART_STATUS_ERROR;
    uint32 value;
    uint32 timeoutTick = Timeout;

    SchM_Enter_Uart_UART_EXCLUSIVE_AREA_00();
    if ((TRUE == uartState->isTxBusy) ||
        ((UART_MODE_HALF_DUPLEX == channelConfig->duplexMode) && (TRUE == uartState->isRxBusy)))
    {
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_00();
        returnValue = UART_STATUS_BUSY;
    }
    else
    {
        uartState->isTxBusy = TRUE;
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_00();
        uartState->transmitStatus = UART_STATUS_BUSY;
        uartState->txBuff = Buffer;
        uartState->txSize = BufferSize;

        /* disable TX empty interrupt and transmission complete interrupt */
        value = readl(baseAddr + UART_INTEN0_OFF);
        value &= ~(BM_INTEN0_TXFWEE | BM_INTEN0_TCE);
        writel(value, baseAddr + UART_INTEN0_OFF);

        if (UART_MODE_HALF_DUPLEX == channelConfig->duplexMode)
        {
            /* enable Tx, disable Rx */
            value = readl(baseAddr + UART_PCR0_OFF);
            value |=  BM_PCR0_TXEN;
            value &=  ~BM_PCR0_RXEN;
            writel(value, baseAddr + UART_PCR0_OFF);
        }

        while (uartState->txSize > 0U)
        {
            value = readl(baseAddr + UART_FSR0_OFF);
            /* check Tx FIFO is not full */
            while ((0U != (value & BM_FSR0_FULL)) &&
                   (timeoutTick > 0))
            {
                value = readl(baseAddr + UART_FSR0_OFF);
                --timeoutTick;
            }
            if (0 == timeoutTick)
            {
                uartState->transmitStatus = UART_STATUS_TIMEOUT;
                break;
            }
            else
            {
                Uart_Ip_PutData(Channel);
                timeoutTick = Timeout;
            }
        }

        if (UART_STATUS_BUSY == uartState->transmitStatus)
        {
            uartState->transmitStatus = UART_STATUS_SUCCESS;
        }

        uartState->isTxBusy = FALSE;
        returnValue = uartState->transmitStatus;
    }

    return returnValue;
}

Std_ReturnType Uart_Ip_SyncReceive(uint8 Channel, uint8* Buffer, uint32 BufferSize, uint32 Timeout)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    Std_ReturnType returnValue = UART_STATUS_ERROR;
    Uart_StatusType errStatus = UART_STATUS_SUCCESS;
    uint32 timeoutTick = Timeout;
    uint32 value;

    SchM_Enter_Uart_UART_EXCLUSIVE_AREA_01();
    if ((TRUE == uartState->isRxBusy) ||
        ((UART_MODE_HALF_DUPLEX == channelConfig->duplexMode) && (TRUE == uartState->isTxBusy)))
    {
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_01();
        returnValue = UART_STATUS_BUSY;
    }
    else
    {
        uartState->isRxBusy = TRUE;
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_01();
        uartState->receiveStatus = UART_STATUS_BUSY;
        uartState->rxBuff = Buffer;
        uartState->rxSize = BufferSize;

        /* disable RX watermark level full interrupt */
        value = readl(baseAddr + UART_INTEN0_OFF);
        value &= (~BM_INTEN0_RXFWFE);
        writel(value, baseAddr + UART_INTEN0_OFF);

        if (UART_MODE_HALF_DUPLEX == channelConfig->duplexMode)
        {
            /* enable Rx, disable Tx */
            value = readl(baseAddr + UART_PCR0_OFF);
            value |=  BM_PCR0_RXEN;
            value &=  ~BM_PCR0_TXEN;
            writel(value, baseAddr + UART_PCR0_OFF);
        }

        while (uartState->rxSize > 0U)
        {
            /* check receive error occur */
            errStatus = Uart_Ip_CheckRecvErr(baseAddr);
            /* check Rx FIFO in not empty */
            while ((0U != (readl(baseAddr + UART_FSR1_OFF) & BM_FSR1_EMPTY)) &&
                   (UART_STATUS_SUCCESS == errStatus) &&
                   (timeoutTick > 0))
            {
                /* check receive error occur */
                errStatus = Uart_Ip_CheckRecvErr(baseAddr);
                --timeoutTick;
            }
            if (0 == timeoutTick)
            {
                uartState->receiveStatus = UART_STATUS_TIMEOUT;
                break;
            }
            timeoutTick = Timeout;

            if (UART_STATUS_SUCCESS != errStatus)
            {
                if ((UART_STATUS_RX_FOVF == errStatus) &&
                (0U == uartState->rxSize))
                {
                    uartState->receiveStatus = UART_STATUS_SUCCESS;
                }
                else
                {
                    uartState->receiveStatus = errStatus;
                }
                break;
            }
            else
            {
                Uart_Ip_GetData(Channel);
            }
        }

        if (UART_STATUS_BUSY == uartState->receiveStatus)
        {
            uartState->receiveStatus = UART_STATUS_SUCCESS;
        }

        uartState->isRxBusy = FALSE;
        returnValue = uartState->receiveStatus;
    }

    if (UART_STATUS_SUCCESS!= returnValue)
    {
        /* clear rx fifo if failed */
        (void)Uart_Ip_ClearRxFifo(baseAddr);
    }

    return returnValue;
}

Std_ReturnType Uart_Ip_AsyncSend(uint8 Channel, const uint8* Buffer, uint32 BufferSize)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    Std_ReturnType returnValue = UART_STATUS_ERROR;
    uint32 value;

    SchM_Enter_Uart_UART_EXCLUSIVE_AREA_02();
    if ((TRUE == uartState->isTxBusy) ||
        ((UART_MODE_HALF_DUPLEX == channelConfig->duplexMode) && (TRUE == uartState->isRxBusy)))
    {
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_02();
        returnValue = UART_STATUS_BUSY;
    }
    else
    {
        uartState->isTxBusy = TRUE;
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_02();

        /* update driver module state */
        uartState->transmitStatus = UART_STATUS_BUSY;
        uartState->txBuff = Buffer;
        uartState->txSize = BufferSize;

        if (UART_MODE_HALF_DUPLEX == channelConfig->duplexMode)
        {
            /* enable Tx, disable Rx */
            value = readl(baseAddr + UART_PCR0_OFF);
            value |=  BM_PCR0_TXEN;
            value &=  ~BM_PCR0_RXEN;
            writel(value, baseAddr + UART_PCR0_OFF);
        }

#if (STD_ON == UART_DMA_SUPPORT)
        if (TRUE == channelConfig->transferUsingDma)
        {
            returnValue = Uart_Ip_SendDataUsingDma(Channel);
        }
        else
#endif /* #if (STD_ON == UART_DMA_SUPPORT) */
        {
            Uart_Ip_SendDataUsingInt(Channel);
            returnValue = UART_STATUS_SUCCESS;
        }
    }

    return returnValue;
}

Std_ReturnType Uart_Ip_AsyncReceive(uint8 Channel, uint8* Buffer, uint32 BufferSize)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    Std_ReturnType returnValue = UART_STATUS_ERROR;
    uint32 value;

    SchM_Enter_Uart_UART_EXCLUSIVE_AREA_03();
    if ((TRUE == uartState->isRxBusy) ||
        ((UART_MODE_HALF_DUPLEX == channelConfig->duplexMode) && (TRUE == uartState->isTxBusy)))
    {
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_03();
        returnValue = UART_STATUS_BUSY;
    }
    else
    {
        uartState->isRxBusy = TRUE;
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_03();

        /* update driver module state */
        uartState->receiveStatus = UART_STATUS_BUSY;
        uartState->rxBuff = Buffer;
        uartState->rxSize = BufferSize;

        if (UART_MODE_HALF_DUPLEX == channelConfig->duplexMode)
        {
            /* enable Rx, disable Tx */
            value = readl(baseAddr + UART_PCR0_OFF);
            value |=  BM_PCR0_RXEN;
            value &=  ~BM_PCR0_TXEN;
            writel(value, baseAddr + UART_PCR0_OFF);
        }

#if (STD_ON == UART_DMA_SUPPORT)
        if (TRUE == channelConfig->transferUsingDma)
        {
            returnValue = Uart_Ip_RecvDataUsingDma(Channel);
        }
        else
#endif /* #if (STD_ON == UART_DMA_SUPPORT) */
        {
            Uart_Ip_RecvDataUsingInt(Channel);
            returnValue = UART_STATUS_SUCCESS;
        }
    }

    return returnValue;
}

Std_ReturnType Uart_Ip_StartRealTimeRecv(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    Std_ReturnType returnValue = UART_STATUS_ERROR;
    uint32 value;

    SchM_Enter_Uart_UART_EXCLUSIVE_AREA_04();
    if ((TRUE == uartState->isRxBusy) ||
        ((UART_MODE_HALF_DUPLEX == channelConfig->duplexMode) && (TRUE == uartState->isTxBusy)))
    {
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_04();
        returnValue = UART_STATUS_BUSY;
    }
    else
    {
        uartState->isRxBusy = TRUE;
        SchM_Exit_Uart_UART_EXCLUSIVE_AREA_04();

        uartState->receiveStatus = UART_STATUS_BUSY;
        uartState->rxBuff = NULL_PTR;
        uartState->rxSize = 0;
        uartState->startRealTimeRecv = TRUE;

        if (UART_MODE_HALF_DUPLEX == channelConfig->duplexMode)
        {
            /* enable Rx, disable Tx */
            value = readl(baseAddr + UART_PCR0_OFF);
            value |=  BM_PCR0_RXEN;
            value &=  ~BM_PCR0_TXEN;
            writel(value, baseAddr + UART_PCR0_OFF);
        }

        /* clear rx fifo */
        returnValue = Uart_Ip_ClearRxFifo(baseAddr);
        if (UART_E_TIMEOUT == returnValue)
        {
            /* convert status */
            returnValue = UART_STATUS_TIMEOUT;
        }
        else
        {
            Uart_Ip_RecvDataUsingInt(Channel);
            returnValue = UART_STATUS_SUCCESS;
        }
    }

    return returnValue;
}

Std_ReturnType Uart_Ip_StopRealTimeRecv(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    Std_ReturnType returnValue = UART_STATUS_ERROR;

    if (TRUE == uartState->startRealTimeRecv)
    {
        uartState->isRxBusy = FALSE;
        uartState->receiveStatus = UART_STATUS_SUCCESS;

        /* clear rx fifo */
        returnValue = Uart_Ip_ClearRxFifo(baseAddr);
        if (UART_E_TIMEOUT == returnValue)
        {
            /* convert status */
            returnValue = UART_STATUS_TIMEOUT;
        }
        else
        {
            Uart_Ip_FinishRecvDataUsingInt(Channel);
            uartState->startRealTimeRecv = FALSE;
            returnValue = UART_STATUS_SUCCESS;
        }
    }
    else
    {
        returnValue = UART_STATUS_STOP_REALTIME_RECV_FAIL;
    }

    return returnValue;
}


void Uart_Ip_AbortSendingData(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = (channelConfig->baseAddr);
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];

    if (TRUE == uartState->isTxBusy)
    {
        if (UART_STATUS_BUSY == uartState->transmitStatus)
        {
            uartState->transmitStatus = UART_STATUS_ABORTED;
        }

#if (STD_ON == UART_DMA_SUPPORT)
        if (TRUE  == channelConfig->transferUsingDma)
        {
            Uart_Ip_FinishSendDataUsingDma(Channel);
        }
        else
#endif /* #if (STD_ON == UART_DMA_SUPPORT) */
        {
            Uart_Ip_FinishSendDataUsingInt(Channel);
        }

        (void)Uart_Ip_ClearTxFifo(baseAddr);
    }
}

void Uart_Ip_AbortReceivingData(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = (channelConfig->baseAddr);
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];

    if ((TRUE == uartState->isRxBusy) && (FALSE == uartState->startRealTimeRecv))
    {
        if (UART_STATUS_BUSY == uartState->receiveStatus)
        {
            uartState->receiveStatus = UART_STATUS_ABORTED;
        }

#if (STD_ON == UART_DMA_SUPPORT)
        if (TRUE  == channelConfig->transferUsingDma)
        {
            Uart_Ip_FinishRecvDataUsingDma(Channel);
        }
        else
#endif /* #if (STD_ON == UART_DMA_SUPPORT) */
        {
            Uart_Ip_FinishRecvDataUsingInt(Channel);
        }

        (void)Uart_Ip_ClearRxFifo(baseAddr);
    }
}

Uart_StatusType Uart_Ip_GetTransmitStatus(uint8 Channel, uint32 * BytesRemaining)
{
    uint8 coreId = Uart_GetCoreId();
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];

    if (NULL_PTR != BytesRemaining)
    {
        if (TRUE == uartState->isTxBusy)
        {
            *BytesRemaining = uartState->txSize;
        }
        else
        {
            *BytesRemaining = 0U;
        }
    }

    return uartState->transmitStatus;
}

Uart_StatusType Uart_Ip_GetReceiveStatus(uint8 Channel, uint32 * BytesRemaining)
{
    uint8 coreId = Uart_GetCoreId();
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];

    if (NULL_PTR != BytesRemaining)
    {
        if (TRUE == uartState->isRxBusy)
        {
            *BytesRemaining = uartState->rxSize;
        }
        else
        {
            *BytesRemaining = 0U;
        }
    }

    return uartState->receiveStatus;
}

void Uart_Ip_IrqHandler(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    uint32 baseAddr = (uint32)(Uart_Handler[coreId]->config->channelConfigs[Channel].baseAddr);
    uint32 intStatus = readl(baseAddr + UART_INTR0_OFF);

    /* Rx error interrupt */
    if (0U != (intStatus & UART_BM_INTR_RX_ERROR))
    {
        Uart_Ip_RxErrIrqHandler(Channel);
    }

    /* Tx error interrupt */
    if (0U != (intStatus & UART_BM_INTR_TX_ERROR))
    {
        Uart_Ip_TxErrIrqHandler(Channel);
    }

    /* Tx complete interrupt */
    if (0U != (intStatus & BM_INTR0_TC))
    {
        Uart_Ip_TxCompleteIrqHandler(Channel);
    }

    /* Rx watermark level full interrupt */
    if (0U != (intStatus & BM_INTR0_RXFWF))
    {
        Uart_Ip_RxFullIrqHandler(Channel);
    }

    /* Auto Baud pass interrupt */
    if (0U != (intStatus & BM_INTR0_ABRPASS))
    {
        Uart_Ip_AutoBaudPassIrqHandler(Channel);
    }

    /* Auto Baud fail interrupt */
    if (0U != (intStatus & BM_INTR0_ABRFAIL))
    {
        Uart_Ip_AutoBaudFailIrqHandler(Channel);
    }
}

uint8 Uart_Ip_GetChannelIdx(uint32 Base)
{
    const Uart_ChannelConfigType * config;
    uint8 channelIdx;
    uint8 coreId = Uart_GetCoreId();

    for (channelIdx = 0; channelIdx < channelMaxIdxOnCore[coreId]; channelIdx++)
    {
        config = &Uart_Handler[coreId]->config->channelConfigs[channelIdx];

        if (config->baseAddr == Base)
        {
            break;
        }
    }

    return channelIdx;
}

/********************************************************************************************************
 *                                  Private Function Declarations                                       *
 *******************************************************************************************************/

static inline Std_ReturnType Uart_Ip_ClearTxFifo(uint32 baseAddr)
{
    volatile uint32 timeout = 0U;
    Std_ReturnType returnValue = E_OK;
    uint32 value;

    value = readl(baseAddr + UART_FCR0_OFF);
    value |= (BM_FCR0_CLRTXF);
    writel(value, baseAddr + UART_FCR0_OFF);

    while ((0U != (value & BM_FCR0_CLRTXF)) &&
           (timeout <= UART_TIMEOUT_CNT))
    {
        value = readl(baseAddr + UART_FCR0_OFF);
        timeout++;
    }

    if (timeout > UART_TIMEOUT_CNT)
    {
        returnValue = UART_E_TIMEOUT;
    }

    return returnValue;
}

static inline Std_ReturnType Uart_Ip_ClearRxFifo(uint32 baseAddr)
{
    volatile uint32 timeout = 0U;
    Std_ReturnType returnValue = E_OK;
    uint32 value;

    value = readl(baseAddr + UART_FCR1_OFF);
    value |= (BM_FCR1_CLRRXF);
    writel(value, baseAddr + UART_FCR1_OFF);

    while ((0U != (value & BM_FCR1_CLRRXF)) &&
           (timeout <= UART_TIMEOUT_CNT))
    {
        value = readl(baseAddr + UART_FCR1_OFF);
        timeout++;
    }

    if (timeout > UART_TIMEOUT_CNT)
    {
        returnValue = UART_E_TIMEOUT;
    }

    return returnValue;
}

static inline void Uart_Ip_WaitTxIdle(uint32 baseAddr)
{
    uint32 value;
    volatile uint32 timeout = 0U;

    value = readl(baseAddr + UART_PSR0_OFF);
    while ((0U != (value & FM_PSR0_IOTX_STATE)) &&
           (timeout <= UART_TIMEOUT_CNT))
    {
        value = readl(baseAddr + UART_PSR0_OFF);
        timeout++;
    }
}

static inline void Uart_Ip_WaitRxIdle(uint32 baseAddr)
{
    uint32 value;
    volatile uint32 timeout = 0U;

    value = readl(baseAddr + UART_PSR0_OFF);
    while ((0U != (value & FM_PSR0_IORX_STATE)) &&
           (timeout <= UART_TIMEOUT_CNT))
    {
        value = readl(baseAddr + UART_PSR0_OFF);
        timeout++;
    }
}

static uint32 Uart_Ip_GetClockFreq(uint8 Channel)
{
    // need modify
    return 83330000U;
}

static inline uint32 Uart_Ip_BaudrateRoundOff(uint32 clkFreq, uint32 baudRate)
{
    uint8  carry = 0;
    uint32 returnValue;

    returnValue = clkFreq * 10U;
    returnValue = returnValue / baudRate;
    carry = (uint8)(returnValue % 10U > 5U);
    returnValue = returnValue / 10U;
    returnValue += carry;

    return returnValue;
}

static void Uart_Ip_PutData(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint16 data16;
    uint8 data8;

    /* data 16 bit */
    if (UART_DATA_BIT_16BIT == channelConfig->dataBit)
    {
        data8 = *(uartState->txBuff);
        writel(data8, baseAddr + UART_TXDR_OFF);

        if (uartState->txSize > 1U)
        {
            data8 = *(uartState->txBuff + 1U);
            uartState->txBuff += 2U;
            uartState->txSize -= 2U;
        }
        else
        {
            data8 = channelConfig->dataFill;
            uartState->txBuff += 1U;
            uartState->txSize -= 1U;
        }
        writel(data8, baseAddr + UART_TXDR_OFF);

    }
    /* data 9 bit */
    else if ((UART_DATA_BIT_9BIT == channelConfig->dataBit) &&
              channelConfig->addrBit == 0U)
    {
        data16 = *(uartState->txBuff) & 0xFFU;

        if (uartState->txSize > 1U)
        {
            data16 |= (*(uartState->txBuff + 1) & 0x1) << 8U;
            uartState->txBuff += 2U;
            uartState->txSize -= 2U;
        }
        else
        {
            uartState->txBuff += 1U;
            uartState->txSize -= 1U;
        }
        writel(data16, baseAddr + UART_TXDR_OFF);
    }
    else
    {
        data8 = *(uartState->txBuff);
        ++uartState->txBuff;
        --uartState->txSize;
        writel(data8, baseAddr + UART_TXDR_OFF);
    }
}

static void Uart_Ip_GetData(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint16 data16;

    /* data 16 bit */
    if (UART_DATA_BIT_16BIT == channelConfig->dataBit)
    {
        *(uartState->rxBuff) = (uint8)readl(baseAddr + UART_RXDR_OFF);

        if (uartState->rxSize > 1U)
        {
            *(uartState->rxBuff + 1U) = (uint8)readl(baseAddr + UART_RXDR_OFF);
            uartState->rxBuff += 2U;
            uartState->rxSize -= 2U;
        }
        else
        {
            /* read dummy data */
            (void)readl(baseAddr + UART_RXDR_OFF);
            uartState->rxBuff += 1U;
            uartState->rxSize -= 1U;
        }
    }
    /* data 9 bit */
    else if ((UART_DATA_BIT_9BIT == channelConfig->dataBit) &&
              channelConfig->addrBit == 0U)
    {
        /* get data */
        data16 = readl(baseAddr + UART_RXDR_OFF) & 0x1FFU;

        *(uartState->rxBuff) = (uint8)data16;
        if (uartState->rxSize > 1U)
        {
            *(uartState->rxBuff + 1U) = data16 >> 8;
            uartState->rxBuff += 2U;
            uartState->rxSize -= 2U;
        }
        else
        {
            *(uartState->rxBuff + 1U) = 0U;
            uartState->rxBuff += 1U;
            uartState->rxSize -= 1U;
        }
    }
    else
    {
        *(uartState->rxBuff) = (uint8)readl(baseAddr + UART_RXDR_OFF);
        ++uartState->rxBuff;
        --uartState->rxSize;
    }
}

static Uart_StatusType Uart_Ip_CheckRecvErr(uint32 baseAddr)
{
    uint32 intStatus = readl(baseAddr + UART_INTR0_OFF);
    Uart_StatusType returnValue = UART_STATUS_SUCCESS;

    /* check Rx error occur */
    if (0U != (intStatus & UART_BM_INTR_RX_ERROR))
    {
        if (0U != (intStatus & BM_INTR0_RXFOVF))
        {
            returnValue = UART_STATUS_RX_FOVF;
        }

        if (0U != (intStatus & BM_INTR0_RXFUDF))
        {
            returnValue = UART_STATUS_RX_FUDF;
        }

        if (0U != (intStatus & BM_INTR0_PARITYERR))
        {
            returnValue = UART_STATUS_PARITY_ERROR;
        }

        if (0U != (intStatus & BM_INTR0_FRAMEERR))
        {
            returnValue = UART_STATUS_FRAMING_ERROR;
        }

        if (0U != (intStatus & BM_INTR0_BAUDRATEERR))
        {
            returnValue = UART_STATUS_BAUDRATE_ERROR;
        }

        if (0U != (intStatus & BM_INTR0_NOISEERR))
        {
            returnValue = UART_STATUS_NOISE_ERROR;
        }

        /* clear Rx error interrupt status */
        writel(UART_BM_INTR_RX_ERROR, baseAddr + UART_INTR0_OFF);
    }
    else
    {
        returnValue = UART_STATUS_SUCCESS;
    }

    return returnValue;
}

static void Uart_Ip_SendDataUsingInt(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint32 value;

    /* Fill Tx FIFO */
    while ((0U == (readl(baseAddr + UART_FSR0_OFF) & BM_FSR0_FULL)) &&
            (0U < uartState->txSize))
    {
        Uart_Ip_PutData(Channel);
    }

    /* Enable Tx related interrupt */
    value = readl(baseAddr + UART_INTEN0_OFF);
    value |= (UART_BM_INTR_TX_ERROR | BM_INTEN0_TCE);
    writel(value, baseAddr + UART_INTEN0_OFF);
}

static void Uart_Ip_RecvDataUsingInt(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    uint32 baseAddr = (Uart_Handler[coreId]->config->channelConfigs[Channel].baseAddr);
    uint32 value;

    /* clear rx related interrupt status */
    writel(UART_BM_INTR_RX_ERROR | BM_INTR0_RXFWF, baseAddr + UART_INTR0_OFF);

    /* Enable Rx error interrupt and Rx FIFO watermark level interrupt */
    value = readl(baseAddr + UART_INTEN0_OFF);
    value |= UART_BM_INTR_RX_ERROR | BM_INTR0_RXFWF;
    writel(value, baseAddr + UART_INTEN0_OFF);
}


static inline void Uart_Ip_FinishSendDataUsingInt(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    uint32 baseAddr = (Uart_Handler[coreId]->config->channelConfigs[Channel].baseAddr);
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint32 value;

    /* Disable TC and Tx error interrupt */
    value = readl(baseAddr + UART_INTEN0_OFF);
    value &= ~(BM_INTR0_TC | UART_BM_INTR_TX_ERROR);
    writel(value, baseAddr + UART_INTEN0_OFF);

    if (UART_STATUS_BUSY == uartState->transmitStatus)
    {
        /* If the transfer is completed, update the transmit status */
        uartState->transmitStatus = UART_STATUS_SUCCESS;
    }

    /* Update the internal busy flag */
    uartState->isTxBusy = FALSE;
}

static inline void Uart_Ip_FinishRecvDataUsingInt(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    uint32 baseAddr = (Uart_Handler[coreId]->config->channelConfigs[Channel].baseAddr);
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint32 value;

    /* Disable Rx error interrupt and Rx FIFO watermark level interrupt */
    value = readl(baseAddr + UART_INTEN0_OFF);
    value &= ~(UART_BM_INTR_RX_ERROR | BM_INTR0_RXFWF);
    writel(value, baseAddr + UART_INTEN0_OFF);

    /* clear rx related interrupt status */
    writel(UART_BM_INTR_RX_ERROR | BM_INTR0_RXFWF, baseAddr + UART_INTR0_OFF);

    if (UART_STATUS_BUSY == uartState->receiveStatus)
    {
        /* If the transfer is completed, update the transmit status */
        uartState->receiveStatus = UART_STATUS_SUCCESS;
    }

    /* Update the internal busy flag */
    uartState->isRxBusy = FALSE;
}

#if (STD_ON == UART_DMA_SUPPORT)
static inline Std_ReturnType Uart_Ip_TxDmaReset(uint32 baseAddr)
{
    volatile uint32 timeout = 0U;
    Std_ReturnType returnValue = E_OK;
    uint32 value;

    value = readl(baseAddr + UART_DMACR_OFF);
    value |= (BM_DMACR_TXDMARST);
    writel(value, baseAddr + UART_DMACR_OFF);

    while ((0U != (value & BM_DMACR_TXDMARST)) &&
           (timeout <= UART_TIMEOUT_CNT))
    {
        value = readl(baseAddr + UART_DMACR_OFF);
        timeout++;
    }

    if (timeout > UART_TIMEOUT_CNT)
    {
        returnValue = UART_E_TIMEOUT;
    }

    return returnValue;
}

static inline Std_ReturnType Uart_Ip_RxDmaReset(uint32 baseAddr)
{
    volatile uint32 timeout = 0U;
    Std_ReturnType returnValue = E_OK;
    uint32 value;

    value = readl(baseAddr + UART_DMACR_OFF);
    value |= (BM_DMACR_RXDMARST);
    writel(value, baseAddr + UART_DMACR_OFF);

    while ((0U != (value & BM_DMACR_RXDMARST)) &&
           (timeout <= UART_TIMEOUT_CNT))
    {
        value = readl(baseAddr + UART_DMACR_OFF);
        timeout++;
    }

    if (timeout > UART_TIMEOUT_CNT)
    {
        returnValue = UART_E_TIMEOUT;
    }

    return returnValue;
}

static Std_ReturnType Uart_Ip_SendDataUsingDma(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    Dma_ChannelConfigType *channelPtr = NULL_PTR;
    Dma_InstanceConfigType dmaALConfigParams;
    Dma_DeviceConfigType dmaConfig;
    Std_ReturnType errorId = E_OK;
    uint32 value;

    errorId = Dma_GetConfigParams(channelConfig->dmaPeripheralId, DMA_UART_TX, DMA_MODULE_UART, &dmaALConfigParams);
    if (E_OK == errorId)
    {
        channelPtr = Dma_RequestChannelWithId(dmaALConfigParams.controller, dmaALConfigParams.channelId);
        if (NULL_PTR == channelPtr)
        {
            errorId = UART_E_DMA_REQUEST_CHAN_ERR;
        }
        else
        {
            /* set dma call back function */
            uartState->dmaTxChannel = channelPtr;
            channelPtr->context = (void *)channelConfig;
            channelPtr->irqCallback = (Dma_IrqHandle)&Uart_Irq_DmaSendComplete;

            (void)Dma_InitConfigChannel(&dmaConfig);
            dmaConfig.direction           = DMA_MEMORY_TO_DEVICE;
            dmaConfig.memsetValue         = 0U;
            dmaConfig.periodLength        = 0U;
            dmaConfig.transaction         = DMA_DEVICE;
            dmaConfig.processMode         = DMA_INTERRUPT;
            dmaConfig.srcAddress          = (uint32)(uartState->txBuff);
            dmaConfig.dstAddress          = baseAddr + UART_TXDR_OFF; /* uart tx fifo address */
            dmaConfig.srcBusWidth         = DMA_BEAT_SIZE_1_BYTE;
            dmaConfig.dstBusWidth         = DMA_BEAT_SIZE_1_BYTE;
            dmaConfig.srcMaxBurst         = DMA_BURST_LENGTH_1;
            dmaConfig.dstMaxBurst         = DMA_BURST_LENGTH_1;
            dmaConfig.srcPortSelect       = DMA_PORT_AXI64;
            dmaConfig.dstPortSelect       = DMA_PORT_AHB32;
            dmaConfig.srcIncDirection     = DMA_BURST_INCREMENTAL;
            dmaConfig.dstIncDirection     = DMA_BURST_FIXED;
            dmaConfig.srcStridePol        = DMA_POSITIVE_OFFSET;
            dmaConfig.dstStridePol        = DMA_POSITIVE_OFFSET;
            dmaConfig.bufferMode          = DMA_SINGLE_BUFFER;
            dmaConfig.loopMode            = DMA_LOOP_MODE_1;
            dmaConfig.flowControl         = DMA_DIR_MEMORY_TO_DEVICE;
            dmaConfig.transferMode        = DMA_TRANSFER_MODE_SINGLE;
            dmaConfig.linkListTriggerMode = DMA_TRIGGER_BY_HARDWARE;
            dmaConfig.customMuxIdFlag     = FALSE;
            dmaConfig.customMuxId         = 119;
            dmaConfig.madCrcMode          = DMA_MAD_CRC;
            errorId = Dma_ConfigChannel(channelPtr, &dmaConfig);
            if (E_OK == errorId)
            {
                errorId = Dma_PrepareTransmission(channelPtr, (uartState->txSize));
                if (E_OK == errorId)
                {
                    /* Enable TxDma */
                    value = readl(baseAddr + UART_DMACR_OFF);
                    value |= (BM_DMACR_TXDMAE);
                    writel(value, baseAddr + UART_DMACR_OFF);

                    Mcal_FlushCache((uint32)(uartState->txBuff), (uartState->txSize));

                    /* Enable Uart Tx error interrupt */
                    value = readl(baseAddr + UART_INTEN0_OFF);
                    value |= (UART_BM_INTR_TX_ERROR);
                    writel(value, baseAddr + UART_INTEN0_OFF);

                    /* start dma transfer */
                    errorId = Dma_Start(channelPtr);
                    if (E_OK != errorId)
                    {
                        /* Error occur. Disable TX error interrupt */
                        value = readl(baseAddr + UART_INTEN0_OFF);
                        value &= ~(UART_BM_INTR_TX_ERROR);
                        writel(value, baseAddr + UART_INTEN0_OFF);
                    }
                }
            }
        }
    }

    return errorId;
}

static Std_ReturnType Uart_Ip_RecvDataUsingDma(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    Dma_ChannelConfigType *channelPtr = NULL_PTR;
    Dma_InstanceConfigType dmaALConfigParams;
    Dma_DeviceConfigType dmaConfig;
    Std_ReturnType errorId = E_OK;
    uint32 value;

    errorId = Dma_GetConfigParams(channelConfig->dmaPeripheralId, DMA_UART_RX, DMA_MODULE_UART, &dmaALConfigParams);
    if (E_OK == errorId)
    {
        channelPtr = Dma_RequestChannelWithId(dmaALConfigParams.controller, dmaALConfigParams.channelId);
        if (NULL_PTR == channelPtr)
        {
            errorId = UART_E_DMA_REQUEST_CHAN_ERR;
        }
        else
        {
            /* set dma call back function */
            uartState->dmaRxChannel = channelPtr;
            channelPtr->context = (void *)channelConfig;
            channelPtr->irqCallback = (Dma_IrqHandle)&Uart_Irq_DmaRecvComplete;

            (void)Dma_InitConfigChannel(&dmaConfig);
            dmaConfig.direction           = DMA_DEVICE_TO_MEMORY;
            dmaConfig.memsetValue         = 0U;
            dmaConfig.periodLength        = 0U;
            dmaConfig.transaction         = DMA_DEVICE;
            dmaConfig.processMode         = DMA_INTERRUPT;
            dmaConfig.srcAddress          = baseAddr + UART_RXDR_OFF; /* uart tx fifo address */
            dmaConfig.dstAddress          = (uint32)(uartState->rxBuff);
            dmaConfig.srcBusWidth         = DMA_BEAT_SIZE_1_BYTE;
            dmaConfig.dstBusWidth         = DMA_BEAT_SIZE_1_BYTE;
            dmaConfig.srcMaxBurst         = DMA_BURST_LENGTH_1;
            dmaConfig.dstMaxBurst         = DMA_BURST_LENGTH_1;
            dmaConfig.srcPortSelect       = DMA_PORT_AHB32;
            dmaConfig.dstPortSelect       = DMA_PORT_AXI64;
            dmaConfig.srcIncDirection     = DMA_BURST_FIXED;
            dmaConfig.dstIncDirection     = DMA_BURST_INCREMENTAL;
            dmaConfig.srcStridePol        = DMA_POSITIVE_OFFSET;
            dmaConfig.dstStridePol        = DMA_POSITIVE_OFFSET;
            dmaConfig.bufferMode          = DMA_SINGLE_BUFFER;
            dmaConfig.loopMode            = DMA_LOOP_MODE_1;
            dmaConfig.flowControl         = DMA_DIR_DEVICE_TO_MEMORY;
            dmaConfig.transferMode        = DMA_TRANSFER_MODE_SINGLE;
            dmaConfig.linkListTriggerMode = DMA_TRIGGER_BY_HARDWARE;
            dmaConfig.customMuxIdFlag     = FALSE;
            dmaConfig.customMuxId         = 119;
            dmaConfig.madCrcMode          = DMA_MAD_CRC;
            errorId = Dma_ConfigChannel(channelPtr, &dmaConfig);
            if (E_OK == errorId)
            {
                errorId = Dma_PrepareTransmission(channelPtr, (uartState->rxSize));
                if (E_OK == errorId)
                {
                    /* Enable RxDma */
                    value = readl(baseAddr + UART_DMACR_OFF);
                    value |= (BM_DMACR_RXDMAE);
                    writel(value, baseAddr + UART_DMACR_OFF);

                    /* Enable Rx error interrupt */
                    value = readl(baseAddr + UART_INTEN0_OFF);
                    value |= UART_BM_INTR_RX_ERROR;
                    writel(value, baseAddr + UART_INTEN0_OFF);

                    errorId = Dma_Start(channelPtr);
                    if (E_OK != errorId)
                    {
                        /* Error occur. Disable RX error interrupt */
                        value = readl(baseAddr + UART_INTEN0_OFF);
                        value &= ~(UART_BM_INTR_RX_ERROR);
                        writel(value, baseAddr + UART_INTEN0_OFF);
                    }
                }
            }
        }
    }

    return errorId;
}

static void Uart_Ip_FinishSendDataUsingDma(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    uint32 baseAddr = (Uart_Handler[coreId]->config->channelConfigs[Channel].baseAddr);
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint32 value;

    (void)Dma_Stop(uartState->dmaTxChannel);
    (void)Dma_ReleaseChannel(uartState->dmaTxChannel);

    /* Disable TxDma */
    value = readl(baseAddr + UART_DMACR_OFF);
    value &= ~(BM_DMACR_TXDMAE);
    writel(value, baseAddr + UART_DMACR_OFF);

    /* Disable Tx error interrupt */
    value = readl(baseAddr + UART_INTEN0_OFF);
    value &= ~(UART_BM_INTR_TX_ERROR);
    writel(value, baseAddr + UART_INTEN0_OFF);

    if (UART_STATUS_BUSY == uartState->transmitStatus)
    {
        /* If the transfer is completed, update the transmit status */
        uartState->transmitStatus = UART_STATUS_SUCCESS;
    }

    /* Update the internal busy flag */
    uartState->isTxBusy = FALSE;
}

static void Uart_Ip_FinishRecvDataUsingDma(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    uint32 baseAddr = (Uart_Handler[coreId]->config->channelConfigs[Channel].baseAddr);
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint32 value;

    (void)Dma_Stop(uartState->dmaRxChannel);
    (void)Dma_ReleaseChannel(uartState->dmaRxChannel);
    Mcal_InvalidateCache((uint32)uartState->rxBuff, uartState->rxSize);

    /* Disable RxDma */
    value = readl(baseAddr + UART_DMACR_OFF);
    value &= ~(BM_DMACR_RXDMAE);
    writel(value, baseAddr + UART_DMACR_OFF);

    /* Disable Rx error interrupt */
    value = readl(baseAddr + UART_INTEN0_OFF);
    value &= ~(UART_BM_INTR_RX_ERROR);
    writel(value, baseAddr + UART_INTEN0_OFF);

    if (UART_STATUS_BUSY == uartState->receiveStatus)
    {
        /* If the transfer is completed, update the transmit status */
        uartState->receiveStatus = UART_STATUS_SUCCESS;
    }

    /* Update the internal busy flag */
    uartState->isRxBusy = FALSE;
}

void Uart_Irq_DmaSendComplete(Dma_ControllerStatusType status, void *context)
{
    Dma_ChannelConfigType * chan = (Dma_ChannelConfigType *)context;
    const Uart_ChannelConfigType * channelConfig = (const Uart_ChannelConfigType *)chan->context;
    uint8 channel;

    channel = Uart_Ip_GetChannelIdx(channelConfig->baseAddr);
    if (DMA_COMPLETED == status)
    {
        Uart_Ip_FinishSendDataUsingDma(channel);

#if (STD_ON == UART_CALLBACK_ENABLE)
        /* invoke callback */
        if (NULL_PTR != channelConfig->callBack)
        {
            channelConfig->callBack(channel, UART_EVENT_SEND_COMPLETE);
        }
#endif /* (STDON == UART_CALLBACK_ENABLE) */
    }
}

void Uart_Irq_DmaRecvComplete(Dma_ControllerStatusType status, void *context)
{
    Dma_ChannelConfigType * chan = (Dma_ChannelConfigType *)context;
    const Uart_ChannelConfigType * channelConfig = (const Uart_ChannelConfigType *)chan->context;
    uint8 channel;

    channel = Uart_Ip_GetChannelIdx(channelConfig->baseAddr);
    if (DMA_COMPLETED == status)
    {
        Uart_Ip_FinishRecvDataUsingDma(channel);

#if (STD_ON == UART_CALLBACK_ENABLE)
        /* invoke callback */
        if (NULL_PTR != channelConfig->callBack)
        {
            channelConfig->callBack(channel, UART_EVENT_RECV_COMPLETE);
        }
#endif /* (STDON == UART_CALLBACK_ENABLE) */
    }
}
#endif /* #if (STD_ON == UART_DMA_SUPPORT) */

static void Uart_Ip_RxErrIrqHandler(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint32 intStatus;
    uint32 intEnStatus;
    boolean isError = FALSE;

    intStatus = readl(baseAddr + UART_INTR0_OFF);
    intEnStatus = readl(baseAddr + UART_INTEN0_OFF);

    if (0U != (intStatus & BM_INTR0_RXFOVF) &&
       (0U != (intEnStatus & BM_INTR0_RXFOVF)))
    {
        uartState->receiveStatus = UART_STATUS_RX_FOVF;
        isError = TRUE;
    }

    if (0U != (intStatus & BM_INTR0_RXFUDF) &&
       (0U != (intEnStatus & BM_INTR0_RXFUDF)))
    {
        uartState->receiveStatus = UART_STATUS_RX_FUDF;
        isError = TRUE;
    }

    if (0U != (intStatus & BM_INTR0_PARITYERR) &&
       (0U != (intEnStatus & BM_INTR0_PARITYERR)))
    {
        uartState->receiveStatus = UART_STATUS_PARITY_ERROR;
        isError = TRUE;
    }

    if (0U != (intStatus & BM_INTR0_FRAMEERR) &&
       (0U != (intEnStatus & BM_INTR0_FRAMEERR)))
    {
        uartState->receiveStatus = UART_STATUS_FRAMING_ERROR;
        isError = TRUE;
    }

    if (0U != (intStatus & BM_INTR0_BAUDRATEERR) &&
       (0U != (intEnStatus & BM_INTR0_BAUDRATEERR)))
    {
        uartState->receiveStatus = UART_STATUS_BAUDRATE_ERROR;
        isError = TRUE;
    }

    if (0U != (intStatus & BM_INTR0_NOISEERR) &&
       (0U != (intEnStatus & BM_INTR0_NOISEERR)))
    {
        uartState->receiveStatus = UART_STATUS_NOISE_ERROR;
        isError = TRUE;
    }

    if (TRUE == isError)
    {
#if (STD_ON == UART_DMA_SUPPORT)
        if (TRUE == channelConfig->transferUsingDma)
        {
            Uart_Ip_FinishRecvDataUsingDma(Channel);
        }
        else
#endif /* #if (STD_ON == UART_DMA_SUPPORT) */
        {
            Uart_Ip_FinishRecvDataUsingInt(Channel);
        }

#if (STD_ON == UART_CALLBACK_ENABLE)
        /* invoke callback */
        if (NULL_PTR != channelConfig->callBack)
        {
            channelConfig->callBack(Channel, UART_EVENT_RX_ERROR);
        }
#endif /* (STDON == UART_CALLBACK_ENABLE) */
    }

    /* clear interrupt status */
    writel(UART_BM_INTR_RX_ERROR, baseAddr + UART_INTR0_OFF);
}

static void Uart_Ip_TxErrIrqHandler(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];

    uartState->transmitStatus = UART_STATUS_TX_FOVF;

    Uart_Ip_AbortSendingData(Channel);

#if (STD_ON == UART_CALLBACK_ENABLE)
    /* invoke callback */
    if (NULL_PTR != channelConfig->callBack)
    {
        channelConfig->callBack(Channel, UART_EVENT_TX_ERROR);
    }
#endif /* (STDON == UART_CALLBACK_ENABLE) */

    /* clear interrupt status */
    writel(UART_BM_INTR_TX_ERROR, baseAddr + UART_INTR0_OFF);
}

static void Uart_Ip_TxCompleteIrqHandler(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];

    if (0U < uartState->txSize)
    {
        /* Fill Tx FIFO */
        while ((0U == (readl(baseAddr + UART_FSR0_OFF) & BM_FSR0_FULL)) &&
                (0U < uartState->txSize))
        {
            Uart_Ip_PutData(Channel);
        }
    }
    else /* (0U == uartState->txSize) transfer complete */
    {
        Uart_Ip_FinishSendDataUsingInt(Channel);

#if (STD_ON == UART_CALLBACK_ENABLE)
        /* invoke callback */
        if (NULL_PTR != channelConfig->callBack)
        {
            channelConfig->callBack(Channel, UART_EVENT_SEND_COMPLETE);
        }
#endif /* (STDON == UART_CALLBACK_ENABLE) */
    }

    /* clear interrupt status */
    writel(BM_INTR0_TC, baseAddr + UART_INTR0_OFF);
}

static void Uart_Ip_RxFullIrqHandler(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint8 recvBuf[256];
    uint8 fifoLen;
    uint8 readByte = 0;

    if (TRUE == uartState->startRealTimeRecv)
    {
        /* get fifo length */
        fifoLen = GFV_FSR1_FILLLVL(readl(baseAddr + UART_FSR1_OFF));

        for (; readByte < fifoLen; readByte++)
        {
            /* read data */
            recvBuf[readByte] = (uint8)readl(baseAddr + UART_RXDR_OFF);
        }

        /* invoke callback */
        if (NULL_PTR != channelConfig->realTimeRxCallBack)
        {
            channelConfig->realTimeRxCallBack(Channel, recvBuf, fifoLen);
        }
    }
    else
    {
        /* read rx fifo until empty */
        while ((0U == (readl(baseAddr + UART_FSR1_OFF) & BM_FSR1_EMPTY)) &&
            (0U < uartState->rxSize))
        {
            Uart_Ip_GetData(Channel);
        }

        if (0U == uartState->rxSize)
        {
            Uart_Ip_FinishRecvDataUsingInt(Channel);

#if (STD_ON == UART_CALLBACK_ENABLE)
            /* invoke callback */
            if (NULL_PTR != channelConfig->callBack)
            {
                channelConfig->callBack(Channel, UART_EVENT_RECV_COMPLETE);
            }
#endif /* (STDON == UART_CALLBACK_ENABLE) */
        }
    }

    /* clear interrupt status */
    writel(BM_INTR0_RXFWF, baseAddr + UART_INTR0_OFF);
}

static void Uart_Ip_AutoBaudPassIrqHandler(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint32 clkFreq;
    uint32 value;

    /* stop receive */
    Uart_Ip_FinishRecvDataUsingInt(Channel);

    /* clear RX FIFO */
    (void)Uart_Ip_ClearRxFifo(baseAddr);

    /* get auto baud rate */
    clkFreq = Uart_Ip_GetClockFreq(Channel);
    value = GFV_PSR1_AUTOBAUDRATE(readl(baseAddr + UART_PSR1_OFF));
    uartState->baudRate = Uart_Ip_BaudrateRoundOff(clkFreq, value);

    uartState->autoBaudState = UART_AUTOBAUD_STATE_PASS;

    /* clear interrupt status */
    writel(BM_INTR0_ABRPASS, baseAddr + UART_INTR0_OFF);
}

static void Uart_Ip_AutoBaudFailIrqHandler(uint8 Channel)
{
    uint8 coreId = Uart_GetCoreId();
    const Uart_ChannelConfigType * channelConfig = &Uart_Handler[coreId]->config->channelConfigs[Channel];
    uint32 baseAddr = channelConfig->baseAddr;
    Uart_StateType * uartState = &Uart_Handler[coreId]->state[Channel];
    uint32 clkFreq;
    uint32 value;

    /* disable autobaud related interrupt */
    value = readl(baseAddr + UART_INTEN0_OFF);
    value &= ~(BM_INTEN0_ABRPASSE | BM_INTEN0_ABRFAILE);
    writel(value, baseAddr + UART_INTEN0_OFF);

    /* disable autobaud */
    value = readl(baseAddr + UART_PCR0_OFF);
    value &= ~(BM_PCR0_ABREN);
    writel(value, baseAddr + UART_PCR0_OFF);

    /* stop receive */
    Uart_Ip_FinishRecvDataUsingInt(Channel);

    /* clear RX FIFO */
    (void)Uart_Ip_ClearRxFifo(baseAddr);

    /* set default baudrate*/
    clkFreq = Uart_Ip_GetClockFreq(Channel);
    uartState->baudRate = channelConfig->baudRate;
    value = Uart_Ip_BaudrateRoundOff(clkFreq, uartState->baudRate);
    value = (readl(baseAddr + UART_PCR1_OFF) & (~FM_PCR1_BAUDRATECNT)) |
            (value & FM_PCR1_BAUDRATECNT);
    writel(value, baseAddr + UART_PCR1_OFF);

    uartState->autoBaudState = UART_AUTOBAUD_STATE_FAIL;

    /* clear interrupt status */
    writel(BM_INTR0_ABRFAIL, baseAddr + UART_INTR0_OFF);
}

#define UART_STOP_SEC_CODE
#include "Uart_MemMap.h"

#ifdef __cplusplus
}
#endif

/* End of file */
